﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.IO;
using System.Threading;

namespace Faust.Andrew.MTG
{
    public partial class MainForm : Form
    {
        private object _lock = new object();

        private string fileName = String.Empty;
        private string connectionString;
        private List<string> _retrievedCards;

        public MainForm()
        {
            InitializeComponent();
        }

        private List<CardSearchParameters> GetParameters()
        {
            List<CardSearchParameters> par = new List<CardSearchParameters>();
            par.Add(new CardSearchParameters() { Rarity = "C" });
            par.Add(new CardSearchParameters() { Rarity = "R" });
            par.Add(new CardSearchParameters() { Rarity = "U" });
            par.Add(new CardSearchParameters() { Rarity = "L" });
            par.Add(new CardSearchParameters() { Rarity = "S" });
            par.Add(new CardSearchParameters() { Rarity = "M" });
            return par;
        }

        private void btnDoStuff_Click(object sender, EventArgs e)
        {
            connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["db"].ConnectionString;
            fileName = System.Configuration.ConfigurationManager.AppSettings["log"];

            _retrievedCards = new List<string>();

            foreach (CardSearchParameters par in GetParameters())
            {
                System.Threading.ThreadPool.QueueUserWorkItem(LoadCardsThread, par);
            }


        }

        private void ReportProgress(string message)
        {
            if (!InvokeRequired)
            {
                lbProgress.Items.Add(message);
                using (TextWriter writer = File.AppendText(fileName))
                {
                    writer.WriteLine(message);
                }
            }
            else
            {
                Invoke(new Action<string>(ReportProgress), new object[] { message });
            }
        }

        private void LoadCardsThread(object state)
        {
            if (state is CardSearchParameters)
            {
                LoadCards((CardSearchParameters)state);    
            }
        }

        private void LoadCards(CardSearchParameters parameters)
        {
            ReportProgress(String.Format("{0}: Starting", parameters.Rarity));
            WebGatherer gatherer = new WebGatherer(false);
            CardSearchResults results = gatherer.FindCards(parameters);

            int pages = 0;
            while (parameters.Page <= results.Pages && results.Cards.Count() > 0)// && pages <= 0)            
            {
                ReportProgress(String.Format("{0}: Page {1} of {2}", parameters.Rarity, parameters.Page, results.Pages));
                List<Card> cardsToLoad = new List<Card>();

                foreach (Card card in results.Cards)
                {
                    if (ShouldLoadCard(card))
                    {
                        cardsToLoad.Add(card);
                    }
                }

                gatherer.LoadCardDetails(cardsToLoad);                
                SaveCards(cardsToLoad, parameters.Rarity, results.Page);
                pages++;

                parameters.Page = parameters.Page + 1;

                Thread.Sleep(2000);
                if (parameters.Page <= results.Pages)                
                {
                    results = gatherer.FindCards(parameters);
                }
            }
            ReportProgress(String.Format("{0}: Finished", parameters.Rarity));
        }


        private bool ShouldLoadCard(Card card)
        {
            lock (_lock)
            {
                if (_retrievedCards.Exists(tempId => card.MultiverseID.Equals(tempId, StringComparison.CurrentCultureIgnoreCase)))
                {
                    return false;
                }
                else
                {
                    _retrievedCards.Add(card.MultiverseID);
                    return true;                    
                }
            }
        }

        private bool SaveCards(List<Card> cards, string rarity, int page)
        {
            try
            {
                using (LinqCardsDataContext context = new LinqCardsDataContext(connectionString))
                {
                    foreach (Card card in cards)
                    {
                        byte[] image = null;
                        if (card.GetImageStream().Length > 0)
                        {
                            Stream stream = card.GetImageStream();
                            stream.Seek(0, SeekOrigin.Begin);
                            image = new byte[stream.Length];

                            stream.Read(image, 0, image.Length);
                        }

                        LinqCard linqCard = new LinqCard()
                        {
                            CardText = card.CardText,
                            CardTypes = card.CardTypes,
                            Color = card.Color,
                            ConvertedManaCost = card.ConvertedManaCost,
                            ConvertedManaCostNumeric = card.ConvertedManaCostNumeric,
                            Expansion = card.Expansion,
                            Image = image,
                            ManaCost = card.ManaCost,
                            MultiverseID = card.MultiverseID,
                            Name = card.Name,
                            Power = card.Power,
                            PowerNumeric = card.PowerNumeric,
                            Quantity = 0,
                            Rarity = card.Rarity,
                            SubType = card.SubType,
                            Toughness = card.Toughness,
                            ToughnessNumeric = card.ToughnessNumeric
                        };

                        context.LinqCards.InsertOnSubmit(linqCard);
                    }

                    context.SubmitChanges();
                }
                return true;
            }
            catch (Exception e)
            {
                ReportProgress(String.Format("{0}: Error on Page {1}; {2}", rarity, page, e.Message));
                return false;
            }
        }
    }
}
